﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.Core.Modelling.Primitives;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Modelling.Components.Constraints
{
    [Serializable]
    class ConnectedComponentsAngleIntervalConstraintForStickConnector : IConstraint
    {
        private AngleInterval angleInterval;

        public ConnectedComponentsAngleIntervalConstraintForStickConnector(AngleInterval angleInterval)
        {
            this.angleInterval = angleInterval;
        }

        #region IConstraint Members

        public bool Check(IComponent component)
        {
            return false;
        }

        public void Fix(IComponent component)
        {
            List<IComponent> componentsToDisconnect = new List<IComponent>();
            StickConnector stickConnector = component as StickConnector;
            foreach (IComponent connectedComponent in component.ConnectedComponents)
            {
                if (connectedComponent is Shpross)
                {
                    Shpross shpross = connectedComponent as Shpross;
                    if (shpross.StartConnectedComponent == component || shpross.EndConnectedComponent == component)
                        continue;

                    IWidePrimitive shprossPrimitive = (IWidePrimitive)connectedComponent.Primitives[0];
                    ModelVector shprossTangent = null;
                    if (stickConnector.Sticked == StickConnectionType.ToUpBorder)
                    {
                        double offset = ((IEndedPrimitive)shprossPrimitive.UpBorder).GetPathLengthFromProjectionToStart(stickConnector.StartPoint);
                        shprossTangent = ((IEndedPrimitive)shprossPrimitive.UpBorder).GetTangent(offset / shprossPrimitive.UpBorder.Length);
                    }
                    else if (stickConnector.Sticked == StickConnectionType.ToDownBorder)
                    {
                        double offset = ((IEndedPrimitive)shprossPrimitive.DownBorder).GetPathLengthFromProjectionToStart(stickConnector.StartPoint);
                        shprossTangent = ((IEndedPrimitive)shprossPrimitive.DownBorder).GetTangent(offset / shprossPrimitive.UpBorder.Length);
                        shprossTangent = shprossTangent.Rotate(new Angle(Math.PI));
                    }
                    else
                        continue;

                    if (double.IsNaN(shprossTangent.X) || double.IsNaN(shprossTangent.Y) || double.IsInfinity(shprossTangent.X) || double.IsNaN(shprossTangent.Y))
                    {
                        componentsToDisconnect.Add(shpross);
                        continue;
                    }

                    Angle currentAngle = ModelCalculations.GetAngleBetweenVectors(shprossTangent, stickConnector.Primitives[0].GetTangent(0), false);
                    if (!shpross.AngleIntervalToForStickedConnection.IsAngleInInterval(currentAngle))
                    {
                        componentsToDisconnect.Add(shpross);
                    }
                    continue;
                }
            }
            foreach (IComponent componentToDisconnect in componentsToDisconnect)
            {
                if (!ConnectionProvider.Disconnect(component, componentToDisconnect))
                    throw new Exception();
                
            }
        }

        private bool enabled = true;
        public bool Enabled
        {
            get
            {
                return enabled;
            }
            set
            {
                enabled = value;
            }
        }

        public ConstraintAction Action
        {
            get { return ConstraintAction.Disconnect; }
        }


        #endregion

        #region ICloneable Members

        public object Clone()
        {
            ConnectedComponentsAngleIntervalConstraintForStickConnector clone = new ConnectedComponentsAngleIntervalConstraintForStickConnector((AngleInterval)angleInterval.Clone());
            clone.Enabled = this.enabled;
            return clone;
        }

        #endregion
    }
}
